package com.itheima.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.bean.Category;
import com.itheima.bean.Dish;
import com.itheima.bean.DishFlavor;
import com.itheima.common.PageParam;
import com.itheima.dao.DishDao;
import com.itheima.dto.DishDto;
import com.itheima.exception.CustomException;
import com.itheima.service.CategoryService;
import com.itheima.service.DishFlavorService;
import com.itheima.service.DishService;
import lombok.extern.java.Log;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.logging.Logger;
import java.util.stream.Collectors;

@Transactional
@Service
@Slf4j
public class DishServiceImpl implements DishService {

    @Autowired
    private DishDao dishDao;

    @Lazy
    @Autowired
    private CategoryService categoryService;

    //注入口味service对象
    @Autowired
    private DishFlavorService dishFlavorService;

    /**
     * 根据分类的id，查询出来该分类的所有菜品
     * @param status
     * @return
     */
    @Override
    public List<DishDto> findByCategoryId(long categoryId ,  Integer status) {
        log.debug("========（）我在打日志呢============（）",categoryId,status);
        //1. 定义条件
        LambdaQueryWrapper<Dish> qw = new LambdaQueryWrapper<>();

        //2. 设置查询条件
        qw.eq(Dish::getCategoryId , categoryId);
        //追加状态的查询条件
        qw.eq(status != null , Dish::getStatus, status);

        //3. 执行菜品的查询
        List<Dish> dishList = dishDao.selectList(qw);

        //4. 要包装每一个菜品和口味数据
        return dishList.stream().map(dish->{

            //4.1 创建DishDto对象
            DishDto dto = new DishDto();

            //4.2 根据菜品的id，去查询这个菜品的口味数据
            List<DishFlavor> flavorList = dishFlavorService.findByDishId(dish.getId());

            //4.3 封装数据： 把口味数据封装到dto里面
            dto.setFlavors(flavorList);

            //4.4 封装数据： 把菜品数据封装到dto里面
            BeanUtils.copyProperties(dish , dto);

            //4.5 返回dto
            return dto;
        }).collect(Collectors.toList());
    }

    /**
     * 分页查询
     *      1. 先把菜品的分页数据给查询出来。但是不能直接就返回菜品数据。这是不够页面展示用的
     *      2. 上面的步骤是直接去查询菜品表，那么会缺少两个数据：  分类的名称 和 口味的数据
     *      3. 要想把分类的名称和口味的数据也查询出来，必须得去查询分类表和口味表
     *          3.1 查询到了菜品的数据【集合】之后，遍历每一个菜品，得到菜品的分类id值，拿着分类的id值去查询分类表
     *              得到了之后，和菜品数据一起打包！
     *          3.2 查询到了菜品的数据【集合】之后，遍历每一个菜品，得到菜品的id值，拿着菜品的id值去查询口味表
     *              得到数据之后，也要和菜品数据一起打包！
     *          3.3 此时可以使用DishDto 来包装这是三个数据： dish本身的数据， 分类名称， 口味数据
     *
     *          3.4 这也就意味着一会分页查询Dish表 得到 IPage<Dish> 这个结果不能直接返回给controller 应该返回
     *              IPage<DishDto>
     *
     *          3.5 这里唯一比较棘手的就是遍历IPage<Dish> 打散内容，封装成IPage<DishDto>
     * @param pageParam
     * @return
     */
    @Override
    public IPage<DishDto> findPage(PageParam pageParam) {

        //1. 构建分页配置
        IPage<Dish> p = new Page<>(pageParam.getPage(), pageParam.getPageSize());

        //2. 定义查询条件
        LambdaQueryWrapper<Dish> qw =new LambdaQueryWrapper<>();

        //2.1 设置条件
        qw.like( pageParam.getName() != null , Dish::getName , pageParam.getName());

        //3. 执行分页
        IPage<Dish> dishIPage = dishDao.selectPage(p, qw);

        //==上面已经把菜品的集合数据查询出来了，但是不能返回它，因为它的数据不充分，要补充数据===

        //4. 遍历每一个菜品
        List<DishDto> dtoList = dishIPage.getRecords().stream().map((dish)->{
            //4.1 查询分类
            Category category = categoryService.findById(dish.getCategoryId());

            //4.2 查询口味
            List<DishFlavor> flavorList = dishFlavorService.findByDishId(dish.getId());

            //4.3 把 dish 和 分类名称 和 口味集合数据 组装成一个全新的对象 DishDto
            DishDto dishDto = new DishDto();
            //4.3.1 填充分类名称
            dishDto.setCategoryName(category.getName());

            //4.3.2 填充口味数据
            dishDto.setFlavors(flavorList);

            //4.3.3 填充菜品数据
            //dishDto.setId(dish.getId());
            //dishDto.setName(dish.getName());
            //dishDto.setImage(dish.getImage());
            //使用工具方法来拷贝同名的属性，从dise身上拷贝到dishDto身上
            BeanUtils.copyProperties(dish , dishDto);

            return dishDto;
        }).collect(Collectors.toList());

        //5. 构建IPage<DishDto> 然后返回
        IPage<DishDto> dtoIPage = new Page<>();

        //5.1 设置集合数据
        dtoIPage.setRecords(dtoList);

        //5.2 设置总记录数
        dtoIPage.setTotal(dishIPage.getTotal());

        return dtoIPage;
    }

    /**
     * 添加菜品数据
     *      1. 从页面传递过来的数据，包含菜品本身的数据，也包含菜品的口味数据
     *          1.1 菜品本身的数据，需要添加到菜品表 dish 里面
     *          1.2 菜品口味数据，要添加到口味表 dish_flavor里面
     *      2. 数据放到两张表的时候，也有添加的顺序要求的。
     *          2.1 先往 菜品 表 添加数据， 因为只有先往菜品表添加数据才能得到这个菜品的id值
     *          2.2 再往 口味 表 添加数据，再执行前面的添加之后，口味的数据就知道它是和什么菜品进行关联了！
     *
     *
     * @param dishDto
     * @return
     */
    @Override
    public int add(DishDto dishDto) {

        //1. 往菜品表里面添加数据
        int row = dishDao.insert(dishDto);

        //2. 往口味表添加数据
        //只有当菜品表添加成功了，并且这个菜品是有口味数据的，才执行这段if操作，否则不执行这段操作！
        if(row > 0 && dishDto.getFlavors()!= null && dishDto.getFlavors().size() > 0 ){

            int row2 = 0 ;

            for (DishFlavor flavor : dishDto.getFlavors()) {

                //设置口味属于哪一种菜
                flavor.setDishId(dishDto.getId());

                //把每一个口味数据，添加到口味表！
                row2 += dishFlavorService.add(flavor);
            }
            return row2 ==  dishDto.getFlavors().size() ? 1 : 0;
        }

        return row;
    }

    /**
     * 更新菜品数据
     *  1. 更新菜品数据不能和以前的更新想法一样，因为它需要涉及到两张表。 菜品表和口味表
     *  2. 先更新菜品表
     *      2.1 这个操作很容易直接就是按照id来更新数据即可
     *
     *  3. 再更新口味表
     *      3.1 口味数据变化比较多，可以多一个口味设置，也可以少一个口味设置，也可以不要口味数据
     *      3.2  如何应对这么多的变化呢？
     *          3.2.1 把口味表里面的这个菜品的所有口味数据全部删除掉！
     *          3.2.2 再把现在从页面传递过来的口味数据，添加到数据库里面。
     *
     * @param dishDto
     * @return
     */
    @Override
    public int update(DishDto dishDto) {
        //1. 先更新菜品表 : 按id来更新。
        int row1 = dishDao.updateById(dishDto);

        //2. 再更新口味表
        if(row1  > 0 ){
            //2.1 先把这个菜品的口味数据删除掉
            dishFlavorService.deleteByDishId(dishDto.getId());


            //2.2 再把这个菜品的口味数据添加进来
            List<DishFlavor> flavorList = dishDto.getFlavors();

            //2.2.1 先判断页面有没有给过来口味数据，如果有，就添加，没有就不用添加了
            if(flavorList != null && flavorList.size() > 0 ){

                int row3 = 0 ;
                //2.2.2 遍历每一个口味数据
                for (DishFlavor dishFlavor : flavorList) {
                    //2.2.3 设置这个口味属于上面的这个菜的口味
                    dishFlavor.setDishId(dishDto.getId());

                    //2.2.4 把口味数据添加到口味表里面去
                    row3 += dishFlavorService.add(dishFlavor);
                }

                return row3 == flavorList.size() ? 1 : 0 ;
            }
        }

        return row1;
    }

    /**
     * 批量删除
     *
     * @param ids
     * @return
     */
    @Override
    public int delete(List<Long> ids) {
        LambdaQueryWrapper<Dish> qw = new LambdaQueryWrapper<>();
        qw.in(Dish::getId, ids);
        qw.eq(Dish::getStatus, 1);


        int count = dishDao.selectCount(qw);
        //如果不能删除，抛出一个业务异常
        if (count > 0) {
            throw new CustomException("套餐正在售卖中,不能删除");
        }

        int row3 = dishDao.deleteBatchIds(ids);

        for (Long id : ids) {
            dishFlavorService.deleteByDishId(id);
        }
        return row3;
    }

    /**
     * 售卖状态更新
     *
     * @param ids
     */
    @Override
    public void updateStop(List<Long> ids,Integer status) {

        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(ids!=null,Dish::getId,ids);
        List<Dish> dishList = dishDao.selectList(queryWrapper);
        for (Dish dish : dishList) {
            dish.setStatus(status);
            dishDao.updateById(dish);
        }



    }
}
